package monte;

import monte.cs.CompetitionSystem;
import monte.exception.NoResultsException;

import java.util.ArrayList;
import java.util.LinkedList;

/**
 * 模拟类
 * 是诸多MatchProcess的一个集合体
 * 是一次模拟的核心控制单元
 */
public class Simulation {
    ArrayList<MatchProcess> processArrayList;
    CompetitionSystem competitionSystem;
    ArrayList<Team> teams;
    int processTimes;
    LinkedList<ProcessResult> processResults;

    /**
     * 创建一次模拟
     *
     * @param processTimes 包含的比赛进程数
     */
    public Simulation(int processTimes) {
        initSimulation(processTimes);
    }

    /**
     * 创建一次模拟 （默认比赛进程数）
     */
    public Simulation() {
        initSimulation(10000);
    }

    /**
     * 内部调用的初始化方法
     *
     * @param processTimes 比赛进程数
     */
    private void initSimulation(int processTimes) {
        this.processArrayList = new ArrayList<>(processTimes);
        this.processTimes = processTimes;
    }

    /**
     * 设置比赛赛制
     *
     * @param competitionSystem 比赛赛制对象
     */
    public void setCompetitionSystem(CompetitionSystem competitionSystem) {
        this.competitionSystem = competitionSystem;
    }

    /**
     * 设置比赛的参赛队伍的数据
     *
     * @param teams 参数队伍的数组 数组中的顺序就是参加比赛的顺序
     */
    public void setTeams(ArrayList<Team> teams) {
        this.teams = teams;
    }

    /**
     * 开始模拟
     *
     * @return 模拟结果
     * @throws NoResultsException 一些导致没有结果的意外：没有配置好一些数据
     */
    public void startSimulation() throws NoResultsException {
        processResults = new LinkedList<>();
        if (this.competitionSystem == null || this.teams == null) {
            throw new NoResultsException("No \"Tournament\" or \"Team\" is configured.");
        }
        for (int i = 0; i < processTimes; i++) {
            MatchProcess process = new MatchProcess(competitionSystem, teams);
            //开始进行模拟
            process.simulate();
            processArrayList.add(process);
        }
        //开始整理之前的每个MatchProcess的结果
        for (int i = 0; i < processTimes; i++) {
            processResults.add(processArrayList.get(i).getResult());
        }
    }

    /**
     * 取得仿真结果
     *
     * @return SimulationResult 返回单次仿真结果
     */
    public SimulationResult getSimulationResult() throws NoResultsException {
        if (processResults == null)
            throw new NoResultsException("还没有开始模拟");
        double totalLossTop = 0;
        double totalLossResult = 0;
        int count = 0;
        for (ProcessResult processResult : processResults) {
            totalLossTop += processResult.getLossTop();
            totalLossResult += processResult.getLossResult();
            count++;
        }
        totalLossTop /= count;
        totalLossResult /= count;
        return new SimulationResult(totalLossResult, totalLossTop);
    }
}